﻿/**
 * Notes: 云操作类库
 * Ver : CCMiniCloud Framework 2.3.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat)
 * Date: 2020-11-14 07:48:00 
 */

const helper = require('./helper.js');
const dataHelper = require('./data_helper.js');
const cacheHelper = require('./cache_helper.js');
const constants = require('../constants/constants.js');
// 完全移除对contentCheckHelper的导入，避免循环依赖
const pageHelper = require('../helpers/page_helper.js');
const timeHelper = require('../helpers/time_helper.js');
const setting = require('../config/projects.js');
const routes = require('../config/routes_config.js');

const CODE = {
	SUCC: 200,
	SVR: 500, //服务器错误  
	LOGIC: 1600, //逻辑错误 
	DATA: 1301, // 数据校验错误 
	HEADER: 1302, // header 校验错误  

	ADMIN_ERROR: 2401, //管理员错误
	WORK_ERROR: 2501, //陪练员错误
	FLOW_ERROR: 3501
};

/**
 * 尝试加载离线数据服务
 * 用于在网络请求失败时提供备用数据
 */
let offlineDataService = null;
try {
  // 尝试导入PLM项目的模拟数据服务
  offlineDataService = require('../projects/plm/services/plm_mock_service.js');
  console.log('成功加载PLM离线数据服务');
} catch (e) {
  console.log('PLM离线数据服务不可用，将只使用在线数据');
}

function callCloudSumbitAsync(route, params = {}, options) {
	if (!route) return null;
	
	return callCloud(route, params, options).then(res => {
		return res.result;
	}).catch(err => {
		return null;
	});
}

async function callCloudSumbit(route, params = {}, options = { title: '提交中...' }) {
	if (!route) throw new Error('Route不能为空');
	
	let title = options && options.title ? options.title : '提交中...';
	let ifFail = options && helper.isDefined(options.ifFail) ? options.ifFail : true; //是否提示失败
	let result = await callCloud(route, params, {
		title: title
	});
	
	if (result.code != CODE.SUCC) {
		if (ifFail) {
			let message = result.msg;
			if (!message) message = '操作失败，请重试';
			
			// 显示基本错误提示（可在UI上看到，但不阻塞代码执行）
			wx.showToast({
				title: message,
				icon: 'none',
				duration: 2000
			});
		}
		
		// 向上抛出错误，让调用者可以捕获并处理
		let error = new Error(result.msg || '操作失败');
		error.code = result.code;
		error.result = result;
		throw error;
	}

	return result;
}

/**
 * 调用云函数获取数据（直接返回数据）
 * @param {*} route 路由
 * @param {*} params 参数
 * @param {*} options 选项
 */
async function callCloudData(route, params = {}, options = {}) {
	if (!helper.isDefined(params.PID)) {
		params.PID = pageHelper.getPID();
		
		// 检查是否有明确的pid选项
		if (options && options.pid) {
			params.PID = options.pid;
			console.log(`[CLOUD] 使用选项中指定的PID: ${options.pid}`);
		}
		
		// 如果是PLM相关接口，确保PID设置正确
		if (route.startsWith('research_project/') || 
			route.startsWith('plm/') || 
			route.startsWith('plm_')) {
			params.PID = 'plm';
			console.log(`[CLOUD] 自动设置PLM接口的PID为: plm`);
		}
	}

	// 删除可能存在的特殊字段，避免脏数据问题
	const keysToDelete = ['_id', 'uid', 'uid_openid', 'USER_ID', '_pid', 'PID'];
	for (let key of keysToDelete) {
		if (params[key] === undefined || params[key] === null || params[key] === '')
			delete params[key];
	}

	// 清理空字符串字段，避免脏数据问题
	for (let key in params) {
		if (params[key] === '') {
			delete params[key];
		}

		// 清理对象中的无效字段，如null, undefined，避免脏数据问题
		if (params[key] !== null && typeof params[key] === 'object' && !Array.isArray(params[key])) {
			for (let subKey in params[key]) {
				if (params[key][subKey] === null || params[key][subKey] === undefined || params[key][subKey] === '') {
					delete params[key][subKey];
				}
			}
			// 如果清理后对象为空，删除整个字段
			if (Object.keys(params[key]).length === 0) {
				delete params[key];
			}
		}
	}

	let PID = pageHelper.getPID();
	console.log('[CLOUD] 发送请求：', route, params);

	// 离线数据支持标志
	const useOfflineData = options && options.useOfflineData !== false; // 默认启用
	// 强制使用云端数据标志 - 添加新选项
	const forceCloud = options && options.forceCloud === true; // 默认不启用
	
	const pid = params.pid || PID;
	
	// 判断是否为PLM项目相关接口
	const isPLMApi = (route.startsWith('plm/') || pid === 'plm');
	
	// 只有在非强制云端模式下才尝试使用离线数据
	if (!forceCloud && isPLMApi && route === 'plm/project_list' && useOfflineData) {
		console.log('[CLOUD] 项目列表请求，尝试使用离线数据');
		try {
			// 导入模拟服务
			const mockService = require('../projects/plm/services/plm_mock_service');
			
			// 调用模拟服务获取数据
			const result = await mockService.getProjectList(params);
			
			if (result && result.code === 0) {
				console.log('[CLOUD] 模拟服务返回结果:', result);
				
				// 确保结果数据格式正确
				if (result.list && Array.isArray(result.list)) {
					// 如果数据已经在预期的格式中(list直接在顶层)，直接返回
					return result;
				} else if (result.data && result.data.list && Array.isArray(result.data.list)) {
					// 如果数据在data.list中，返回data
					return result.data;
				} else {
					console.warn('[CLOUD] 模拟服务返回的数据格式不符合预期:', result);
					return {
						list: [],
						total: 0,
						page: 1,
						size: 20
					};
				}
			}
		} catch (e) {
			console.warn('[CLOUD] 使用模拟服务失败:', e);
		}
	}
	
	// 如果是PLM项目接口，优先尝试从本地缓存获取数据(除非强制云端模式)
	if (!forceCloud && isPLMApi && useOfflineData) {
		// 尝试检查本地是否有缓存数据
		const cacheKey = `cloud_cache_${route}_${JSON.stringify(params)}`;
		const cachedData = cacheHelper.get(cacheKey);
		if (cachedData) {
			console.log('[CLOUD] 使用缓存数据：', route, cachedData);
			
			// 如果设置了静默加载（不显示加载状态），直接返回缓存数据
			if (options && options.hasLoading === false) {
				return cachedData;
			}
		}
	}

	if (options && options.doFail) {
		try {
			let result = await wx.cloud.callFunction({
				name: 'mcloud',
				data: {
					route,
					params,
					PID,
					cloudID
				}
			});
			if (result && result.result) {
				const restData = result.result;
				if (restData.code == CODE.SUCC) {
					console.log('[CLOUD] 请求成功：', route, restData);
					
					// 缓存成功的PLM数据
					if (isPLMApi && useOfflineData) {
						const cacheKey = `cloud_cache_${route}_${JSON.stringify(params)}`;
						cacheHelper.set(cacheKey, restData.data, 3600); // 缓存1小时
					}
					
					return restData.data;
				} else {
					console.log('[CLOUD] 逻辑错误：', restData);
					if (restData.msg.includes('脏数据')) {
						wx.showModal({
							title: '数据校验错误',
							content: '提交的数据包含不兼容或无效字段，请联系管理员解决此问题。',
							showCancel: false
						});
					}
					
					// 如果是PLM接口且启用了离线数据，尝试提供离线数据
					if (isPLMApi && useOfflineData) {
						console.log('[CLOUD] 尝试使用离线数据服务提供数据');
						try {
							// 导入模拟服务
							const mockService = require('../projects/plm/services/plm_mock_service');
							
							// 调用模拟服务获取数据
							if (route === 'plm/project_list') {
								const result = await mockService.getProjectList(params);
								if (result && result.code === 0) {
									console.log('[CLOUD] 模拟服务返回替代数据:', result);
									return result.data;
								}
							} else if (route === 'plm/project_detail' && params.id) {
								const result = await mockService.getProjectDetail(params.id);
								if (result && result.code === 0) {
									console.log('[CLOUD] 模拟服务返回替代数据:', result);
									return result.data;
								}
							}
						} catch (e) {
							console.warn('[CLOUD] 使用模拟服务失败:', e);
						}
					}
					
					options.doFail(restData);
					return null;
				}
			}
			
			// 如果是PLM接口且启用了离线数据，尝试提供离线数据
			if (isPLMApi && useOfflineData) {
				console.log('[CLOUD] 请求失败，尝试使用离线数据服务提供数据');
				try {
					// 导入模拟服务
					const mockService = require('../projects/plm/services/plm_mock_service');
					
					// 调用模拟服务获取数据
					if (route === 'plm/project_list') {
						const result = await mockService.getProjectList(params);
						if (result && result.code === 0) {
							console.log('[CLOUD] 模拟服务返回替代数据:', result);
							return result.data;
						}
					} else if (route === 'plm/project_detail' && params.id) {
						const result = await mockService.getProjectDetail(params.id);
						if (result && result.code === 0) {
							console.log('[CLOUD] 模拟服务返回替代数据:', result);
							return result.data;
						}
					}
				} catch (e) {
					console.warn('[CLOUD] 使用模拟服务失败:', e);
				}
			}
			
			options.doFail(result);
			return null;
		} catch (err) {
			console.error('[CLOUD] 请求错误：', err);
			
			// 如果是PLM接口且启用了离线数据，尝试提供离线数据
			if (isPLMApi && useOfflineData) {
				console.log('[CLOUD] 请求出错，尝试使用离线数据服务提供数据');
				try {
					// 导入模拟服务
					const mockService = require('../projects/plm/services/plm_mock_service');
					
					// 调用模拟服务获取数据
					if (route === 'plm/project_list') {
						const result = await mockService.getProjectList(params);
						if (result && result.code === 0) {
							console.log('[CLOUD] 模拟服务返回替代数据:', result);
							return result.data;
						}
					} else if (route === 'plm/project_detail' && params.id) {
						const result = await mockService.getProjectDetail(params.id);
						if (result && result.code === 0) {
							console.log('[CLOUD] 模拟服务返回替代数据:', result);
							return result.data;
						}
					}
				} catch (e) {
					console.warn('[CLOUD] 使用模拟服务失败:', e);
				}
			}
			
			options.doFail(err);
			return null;
		}
	} else {
		return callCloud(route, params, options);
	}
}

/**
 * 尝试从离线数据服务获取数据
 * @param {string} route 路由
 * @param {object} params 参数
 * @returns {object|null} 离线数据或null
 */
function _tryGetOfflineData(route, params) {
	try {
		if (!offlineDataService) return null;
		
		// 将路由映射到离线数据服务的方法
		if (route === 'plm/project_list') {
			// 获取结果（可能是Promise或直接返回值）
			const result = offlineDataService.getProjectList(params);
			
			// 检查result是否为Promise
			if (result && typeof result.then === 'function') {
				console.log('[CLOUD] 模拟服务返回了Promise，等待解析');
				// 如果是Promise，返回其解析后的结果
				return result.then(data => {
					return _processOfflineProjectData(data);
				});
			} else {
				// 如果不是Promise，直接处理
				console.log('[CLOUD] 模拟服务返回了直接结果');
				return _processOfflineProjectData(result);
			}
		}
		
		if (route === 'plm/project_detail' && params.id) {
			const result = offlineDataService.getProjectDetail(params.id);
			
			if (result && typeof result.then === 'function') {
				return result.then(data => {
					if (data && data.code === 0) {
						return data.data;
					}
					return null;
				});
			} else {
				if (result && result.code === 0) {
					return result.data;
				}
				return null;
			}
		}
		
		return null;
	} catch (error) {
		console.error('[CLOUD] 获取离线数据失败：', error);
		return null;
	}
}

/**
 * 处理离线项目列表数据
 * @param {object} data 原始数据
 * @returns {object} 处理后的数据
 */
function _processOfflineProjectData(data) {
	// 确保数据格式正确
	if (!data) {
		console.log('[CLOUD] 离线数据为空');
		return null;
	}

	console.log('[CLOUD] 处理原始离线数据:', data);
	
	// 直接返回list结构的数据（模拟服务标准格式）
	if (data.list && Array.isArray(data.list)) {
		console.log('[CLOUD] 找到顶层list结构，直接返回');
		return data;
	}
	
	// 处理包装在data中的数据（云函数标准格式）
	if (data.data) {
		if (Array.isArray(data.data)) {
			console.log('[CLOUD] 发现data数组，构造标准格式');
			return {
				list: data.data,
				total: data.data.length,
				page: 1,
				size: data.data.length
			};
		}
		
		if (data.data.list && Array.isArray(data.data.list)) {
			console.log('[CLOUD] 使用data.list结构');
			return data.data;
		}
		
		console.log('[CLOUD] data存在但格式不符合预期');
	}
	
	// 处理数据本身是数组的情况
	if (Array.isArray(data)) {
		console.log('[CLOUD] 数据本身是数组，构造标准格式');
		return {
			list: data,
			total: data.length,
			page: 1,
			size: data.length
		};
	}
	
	// 返回空结果
	console.log('[CLOUD] 数据格式无法处理，返回空结果');
	return {
		list: [],
		total: 0,
		page: 1,
		size: 20
	};
}

function callCloud(route, params = {}, options = {}) {
	if (!route || typeof route !== 'string') {
		console.error('[CLOUD] 路由不能为空或格式不正确, route=', route);
		return Promise.reject(new Error('路由不能为空或格式不正确'));
	}
	
	let title = '加载中';
	let loading = true;
	let doFail = null;
	let timeout = null;
	
	// 离线数据支持标志 - 修复options未定义问题
	const useOfflineData = options && options.useOfflineData !== false; // 默认启用
	const pid = params.pid || pageHelper.getPID();
	const isPLMApi = (route.startsWith('plm/') || pid === 'plm');

	if (options && options.doFail) {
		doFail = options.doFail;
	}

	//loading
	if (options && (options.loading == false || options.loading == true))
		loading = options.loading;

	if (options && (helper.isDefined(options.title)))
		title = options.title;
		
	// 获取超时时间（毫秒）
	if (options && options.timeout) {
		timeout = options.timeout;
	}

	let hint = loading;
	if (hint) {
		if (title == 'bar')
			wx.showNavigationBarLoading();
		else
			wx.showLoading({
				title: title,
				mask: true
			});
	}

	// 尝试使用缓存数据（仅对PLM项目接口）
	if (isPLMApi && useOfflineData) {
		const cacheKey = `cloud_cache_${route}_${JSON.stringify(params)}`;
		const cachedData = cacheHelper.get(cacheKey);
		if (cachedData) {
			console.log('[CLOUD] 使用缓存数据：', route, cachedData);
			return Promise.resolve({
				code: CODE.SUCC,
				data: cachedData
			});
		}
	}

	if (!params) params = {};

	// 补全参数
	if (!helper.isDefined(params.PID)) {
		params.PID = pageHelper.getPID();
	}

	// 清理数据
	for (let k in params) {
		if (params[k] === null || params[k] === undefined) {
			delete params[k];
		}
	}

	let cloudID = timeHelper.getTimeID();

	let promise = new Promise(function(resolve, reject) {
		let cloudFunc = wx.cloud.callFunction({
			name: 'mcloud',
			data: {
				route: route,
				params,
				cloudID
			},
			success: function(res) {
				if (res && res.result) {
					const result = res.result;
					if (result.code == CODE.SUCC) {
						// 缓存成功的PLM数据
						if (isPLMApi && useOfflineData) {
							const cacheKey = `cloud_cache_${route}_${JSON.stringify(params)}`;
							cacheHelper.set(cacheKey, result.data, 3600); // 缓存1小时
						}
					}
					
					resolve(result);
				} else {
					reject('API异常,请重试');
				}
			},
			fail: function(err) {
				// 判断是否网络连接失败
				if (err.errMsg && (
						err.errMsg.includes('request:fail') || 
						err.errMsg.includes('timeout') || 
						err.errMsg.includes('connectSocket:fail'))) {
					console.error('[CLOUD] 网络连接失败:', err);
					
					// 尝试使用离线数据（仅对PLM项目接口）
					if (isPLMApi && useOfflineData && offlineDataService) {
						console.log('[CLOUD] 网络连接失败，尝试使用离线数据');
						const offlineData = _tryGetOfflineData(route, params);
						if (offlineData) {
							console.log('[CLOUD] 使用离线数据成功:', offlineData);
							resolve({
								code: CODE.SUCC,
								data: offlineData
							});
							return;
						}
					}
					
					reject('网络连接失败,请重试');
				} else {
					reject('API异常,请重试');
				}
			},
			complete: function() {
				if (hint) {
					if (title == 'bar')
						wx.hideNavigationBarLoading();
					else
						wx.hideLoading();
				}
			}
		});

		// 如果设置了超时时间，添加超时处理
		if (timeout) {
			setTimeout(() => {
				// 添加防御性检查，确保cloudFunc存在且其abort方法可用
				if (cloudFunc && typeof cloudFunc.abort === 'function') {
					cloudFunc.abort(); // 取消请求
				}
				
				reject('请求超时，请重试');
				
				// 检查是否有缓存数据（仅对PLM项目接口）
				if (isPLMApi && useOfflineData) {
					const cacheKey = `cloud_cache_${route}_${JSON.stringify(params)}`;
					const cachedData = cacheHelper.get(cacheKey);
					if (cachedData) {
						console.log('[CLOUD] 请求超时，使用缓存数据:', cachedData);
						resolve({
							code: CODE.SUCC,
							data: cachedData
						});
					}
				}
			}, timeout);
		}
	});
	
	return promise;
}

async function dataList(that, listName, route, params, options, isReverse = false) {

	console.log('dataList begin');

	if (!helper.isDefined(that.data[listName]) || !that.data[listName]) {
		let data = {};
		data[listName] = {
			page: 1,
			size: 20,
			list: [],
			count: 0,
			total: 0,
			oldTotal: 0
		};
		that.setData(data);
	}

	//改为后台默认控制
	//if (!helper.isDefined(params.size))
	//	params.size = 20;

	if (!helper.isDefined(params.isTotal))
		params.isTotal = true;

	let page = params.page;
	let count = that.data[listName].count;
	if (page > 1 && page > count) {
		wx.showToast({
			duration: 500,
			icon: 'none',
			title: '没有更多数据了',
		});
		return;
	}

	for (let key in params) {
		if (!helper.isDefined(params[key]))
			delete params[key];
	}

	let oldTotal = 0;
	if (that.data[listName] && that.data[listName].total)
		oldTotal = that.data[listName].total;
	params.oldTotal = oldTotal;

	// 云函数调用 
	await callCloud(route, params, options).then(function (res) {
		console.log('cloud begin');

		let dataList = res.data;
		let tList = that.data[listName].list;

		if (dataList.page == 1) {
			tList = res.data.list;
		} else if (dataList.page > that.data[listName].page) {
			if (isReverse)
				tList = res.data.list.concat(tList);
			else
				tList = tList.concat(res.data.list);
		} else
			return;

		dataList.list = tList;
		let listData = {};
		listData[listName] = dataList;

		that.setData(listData);

		console.log('cloud END');
	}).catch(err => {
		console.log(err)
	});

	console.log('dataList END');

}

async function getTempFileURLOne(fileID) {
	if (!fileID) return '';

	let result = await wx.cloud.getTempFileURL({
		fileList: [fileID],
	})
	if (result && result.fileList && result.fileList[0] && result.fileList[0].tempFileURL)
		return result.fileList[0].tempFileURL;
	return '';
}

async function transTempPics(imgList, dir, id, prefix = '') {
	if (setting.IS_DEMO) return imgList; 

	if (prefix && !prefix.endsWith('_')) prefix += '_';
	if (!id) id = timeHelper.time('YMD');

	for (let i = 0; i < imgList.length; i++) {

		let filePath = imgList[i];
		let ext = filePath.match(/\.[^.]+?$/)[0];

		// 是否为临时文件
		if (filePath.includes('tmp') || filePath.includes('temp') || filePath.includes('wxfile')) {

			let rd = prefix + dataHelper.genRandomNum(1000000, 9999999);
			let cloudPath = id ? dir + id + '/' + rd + ext : dir + rd + ext;

			if (pageHelper.getPID())
			cloudPath = pageHelper.getPID() + '/' + cloudPath;


			await wx.cloud.uploadFile({
				cloudPath,
				filePath: filePath, // 文件路径
			}).then(res => {
				imgList[i] = res.fileID;
			}).catch(error => {
				// handle error TODO:剔除图片
				console.error(error);
			})
		}
	}

	return imgList;
}

async function transRichEditorTempPics(content, dir, id, route) {

	let imgList = [];
	for (let k = 0; k < content.length; k++) {
		if (content[k].type == 'img') {
			imgList.push(content[k].val);
		}
	}

	// 图片上传到云空间
	imgList = await transTempPics(imgList, dir, id, 'rich');

	// 更新图片地址
	let imgIdx = 0;
	for (let k = 0; k < content.length; k++) {
		if (content[k].type == 'img') {
			content[k].val = imgList[imgIdx];
			imgIdx++;
		}
	}

	// 更新本记录的图片信息
	let params = {
		id,
		content
	}

	try {
		await callCloudSumbit(route, params);
		return content;
	} catch (e) {
		console.error(e);
	}

	return [];
}

async function transCoverTempPics(imgList, dir, id, route) {
	// 图片上传到云空间
	imgList = await transTempPics(imgList, dir, id, 'cover');

	// 更新本记录的图片信息
	let params = {
		id,
		imgList: imgList
	}

	try {
		let res = await callCloudSumbit(route, params);
		return res.data.urls;
	} catch (err) {
		console.error(err);
	}
}

async function transFormsTempPics(forms, dir, id, route) {
	wx.showLoading({
		title: '提交中...',
		mask: true
	});

	let hasImageForms = [];
	for (let k = 0; k < forms.length; k++) {
		if (forms[k].type == 'image') {
			forms[k].val = await transTempPics(forms[k].val, dir, id, 'image');
			hasImageForms.push(forms[k]);
		}
		else if (forms[k].type == 'content') {
			let contentVal = forms[k].val;
			for (let j in contentVal) {
				if (contentVal[j].type == 'img') {
					let ret = await transTempPics([contentVal[j].val], dir, id, 'content');
					contentVal[j].val = ret[0];
				}
			}
			hasImageForms.push(forms[k]);
		}
		else if (forms[k].type == 'file') {
			let fileVal = forms[k].val;
			for (let j in fileVal) {
				let ret = await transTempPics([fileVal[j].path], dir, id, 'file');
				fileVal[j].path = ret[0];
			}
			hasImageForms.push(forms[k]);
		}
	}

	if (hasImageForms.length == 0) return;

	let params = {
		id,
		hasImageForms
	}

	try {
		await callCloudSumbit(route, params);
	} catch (err) {
		console.error(err);
	}
}

async function transTempPicOne(img, dir, id, isCheck = true) {

	if (isCheck) {
		wx.showLoading({
			title: '图片校验中',
			mask: true
		});
		let check = await contentCheckHelper.imgCheck(img);
		if (!check) {
			wx.hideLoading();
			return pageHelper.showModal('不合适的图片, 请重新上传', '温馨提示');
		}
		wx.hideLoading();
	}

	let imgList = [img];
	imgList = await transTempPics(imgList, dir, id);

	if (imgList.length == 0)
		return '';
	else {
		return imgList[0];
	}
}

module.exports = {
	CODE,
	dataList,
	callCloud,
	callCloudSumbit,
	callCloudData,
	callCloudSumbitAsync,
	transTempPics,
	transRichEditorTempPics,
	transCoverTempPics,
	transFormsTempPics,
	getTempFileURLOne,
	transTempPicOne
};
